package com.gopay.checkorder.service.task;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BisBankOrderQueryDAO;
import com.gopay.checkorder.service.BankOrderService;
import com.gopay.checkorder.service.alarm.OrderAlarmDataCollector;
import com.gopay.checkorder.service.alarm.OrderAlarmRecordStorage;
import com.gopay.checkorder.service.sentinel.BcdlOrderSentinel;
import com.gopay.checkorder.service.task.thread.batch.CheckIcbcOrderBcdlThread;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.bank.BankOrderType;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.order.dao.CommonQueryDAO;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.NamedThreadFactory;
import com.gopay.common.util.StringTools;
import com.gopay.gass.service.GassPayRemoteService;

/**
 * 工行批量对账任务
 *
 * @author lilili
 * @data 
 */
public class IcbcBcdlOrderCheckBatchTaskImpl  implements Task {

	private final static Logger logger = LoggerFactory
			.getLogger(IcbcBcdlOrderCheckBatchTaskImpl.class);
	
	private int maxThreadCount;
	
	private int pageSize;

	private ExecutorService threadPool;
	
	@Resource(name = "bisBankOrderQueryDAO")
	private BisBankOrderQueryDAO bisBankOrderQueryDAO;

	@Resource(name = "gassPayService")
	private GassPayRemoteService gassPayService;
	
	@Resource(name = "commonQueryDAO")
	private CommonQueryDAO commonQueryDAO;

	private String bank;

	private String across;
	
	private String label;
	
	private BcdlOrderSentinel sentinel;
	
	@PostConstruct
	public void threadPoolCreate() {
		threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(maxThreadCount, new NamedThreadFactory("IcbcBcdlOrderCheckBatchTaskImpl--"+across));
	}

	private void printLog(StopWatch sw, String bank, String prefix) {
		sw.split();
		logger.error(prefix + "------,bank=" + bank+  ",耗时="
				+ sw.getSplitTime());
	}
	
	@Override
	public void doTask() {
	    logger.info("工行银企直连批量对账job--开始，bank="+bank);
        process(bank);
        logger.info("工行银企直连批量对账job--结束，bank="+bank);
	}


	/**
	 * 任务执行
	 */
	public void process(String bank) {
		try {
			StopWatch sw = new StopWatch();
			sw.start();
			printLog(sw, bank,"IcbcBcdlOrderCheckBatchTaskImpl------start");

			int pageIndex = 1;

			checkBefore();

			List<String> list = getCheckOrder(pageIndex, pageSize);
			printLog(sw, bank,"IcbcBcdlOrderCheckBatchTaskImpl------list.size()=" + list.size()+ ",pageIndex=" + pageIndex);

			// 同步锁存器
			CountDownLatch latch = new CountDownLatch(list.size());

			// 线程池中线程全部参与
			for (String packetNo:list) {

				CheckIcbcOrderBcdlThread thread = new CheckIcbcOrderBcdlThread(label, bank, packetNo, latch, sentinel, gassPayService);
				threadPool.execute(thread);

			}

			// 同步锁存器等待所有线程执行完成
			if (!latch.await(118, TimeUnit.SECONDS)) {
				logger.error("同步锁存器等待超时了 latch.count=" + latch.getCount());
				threadPool.awaitTermination(1, TimeUnit.SECONDS);
			}

			printLog(sw, bank,"IcbcBcdlOrderCheckBatchTaskImpl------end");
			sw.stop();

		} catch (Throwable t) {
			logger.error("执行对单Task时出现异常", t);
		}
	}

	/**
     * 
     */
	private void checkBefore() {
	}

	/**
	 * 待对账订单笔数
	 * 
	 * @param orderStatus
	 * @param totalCheckTimes
	 * @return
	 */
	/*
	 * protected int getCheckOrderCount(String orderStatus){ int resCount =
	 * bisBankOrderQueryDAO.getCheckOrderCountByBank(orderStatus,BANK); if
	 * (resCount > MAX_SIZE) { resCount = MAX_SIZE; } return resCount; }
	 */
	/**
	 * 分页查询对账记录
	 * 
	 * @param orderStatus
	 * @param totalCheckTimes
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 */
	protected List<String> getCheckOrder(int pageIndex, int pageSize) {
		List<String> packetNos = new ArrayList<String>();
		List<Object[]> list = getCheckBcdlOrderByBank(bank, BankOrderStatus.PROCESS, across, pageIndex, pageSize);
		for (Object[] packetNo : list) {
			logger.error("packetNo:" + packetNo[0]);
			String dealPacketNo = StringTools.checkNulltoString(packetNo[0]);
			packetNos.add(dealPacketNo);
		}
		return packetNos;
	}

	public List<Object[]> getCheckBcdlOrderByBank(String bank, String orderStatus, String across, int pageIndex, int pageSize) {
		StringBuffer sql = new StringBuffer(250);
		sql.append("select o.PACKET_NO,count(0) from BIS_BANK_MAIN_ORDER b ");
		if (StringUtils.isNotBlank(across) || "ICBC".equals(bank)) {
			sql.append(" left join BIS_BANK_BCDL_ORDER o on o.gopay_out_order_id = b.gopay_out_order_id ");
		}
		sql.append(" where b.ORDER_STATUS = :orderStatus ");
		sql.append(" and b.BANK_BIZ_PROD_CODE = :bankBizProdCode ");
		  // 获取订单增加渠道码条件
        sql.append(" and b.INTRFACE_CHANNEL_CODE = :interfaceChennelCode ");
		sql.append(" and b.ORDER_TYPE = :orderType ");
		sql.append(" and b.GOPAY_BANK_CODE = :bankCode ");
		if (StringUtils.isNotBlank(across)) {
		    sql.append(" and o.IS_CROSSBANK = :across ");
		}
		sql.append(" and b.TOTAL_CHECK_TIMES = :totalCheckTimes ");
		sql.append(buildBCDLTimeClause());
		sql.append(" group by o.PACKET_NO ");

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("orderStatus", orderStatus);
		params.put("bankBizProdCode", BisBankBusinessProd._09.value);
		params.put("interfaceChennelCode", BisBankInterfaceChannel._00.value);
		params.put("orderType", BankOrderType.GOPAY_BIS_ORDER);
		params.put("bankCode", bank);
		if(StringUtils.isNotBlank(across)){
            params.put("across", across);
        }
		params.put("totalCheckTimes",0);
		List<Object[]> list = commonQueryDAO.findBySql(sql.toString(), params, pageIndex, pageSize);
		return list;
	}
	
	 private String buildBCDLTimeClause(){
	        Calendar calendar = Calendar.getInstance();
	        
	        //开始时间--最近1天
	        calendar.setTime(new Date());
	        calendar.add(Calendar.DAY_OF_MONTH, -1);
	        String beginTime=DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss");
	        //结束时间--当前时间5分钟前
	        calendar = Calendar.getInstance();
	        calendar.add(Calendar.MINUTE, -2);
	        String endTime=DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss");
	        
	        StringBuilder sb=new StringBuilder();
	        sb.append(" and SEND_BANK_TM >to_date('"+beginTime+"','yyyyMMddHH24miss') ");
	        sb.append(" and SEND_BANK_TM <=to_date('"+endTime+"','yyyyMMddHH24miss') ");
	        
	        return sb.toString();
	    }

	public void setMaxThreadCount(int maxThreadCount) {
		this.maxThreadCount = maxThreadCount;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public void setBank(String bank) {
		this.bank = bank;
	}
	
	public void setLabel(String label) {
		this.label = label;
	}

	public void setAcross(String across) {
		this.across = across;
	}

	public void setSentinel(BcdlOrderSentinel sentinel) {
		this.sentinel = sentinel;
	}
}
